import logging
import allure
from utils.send_request import send_jdbc_request
from utils.get_keywords import GetKeywords
from utils.regex import *


class Extractor(object):
    """抽象提取器类"""

    # 1.观察各个函数的参数
    def __init__(self, case, all_vars):
        """所有的方法都需要的参数"""
        self.case = case
        self.all_vars = all_vars

    def extract(self, res=None):
        raise NotImplementedError("所有的子类必须实现extract方法")

    def log_extraction(self, extraction_type, data):
        """日志打印抽离"""
        logging.info(f"4.{extraction_type}, 根据{data}提取数据, 此时全局变量为: {self.all_vars}")

    def add_to_all_vars(self, key, value):
        """把数据存入全局变量的方法"""
        if key in self.all_vars:
            logging.warning(f"提取器：全局变量内的{key}已经存在，目前是替换值")
        self.all_vars[key] = value

    def eval_data(self, data_str):
        """三目运算"""
        """eval封装"""
        try:
            return eval(data_str) if data_str else None
        except Exception as e:
            logging.error(f"提取器使用eval的时候抛出异常，数据是：{data_str}，异常是：{e}。请检查excel里面是否按照字典的格式写的")


class JsonExtractor(Extractor):
    """json提取类"""

    @allure.step("4.JSON提取")
    def extract(self, res):
        if self.case["jsonExData"]:
            # 首先要把 jsonExData 的 key, value 拆开
            for key, value in self.eval_data(self.case["jsonExData"]).items():
                value = GetKeywords.get_keyword(res, value)
                self.add_to_all_vars(key, value)
            self.log_extraction("JSON提取", self.case["jsonExData"])


class JDBCExtractor(Extractor):
    """jdbc提取类"""

    @allure.step("4.JDBC提取")
    def extract(self):
        if self.case["sqlExData"]:
            for key, value in self.eval_data(self.case["sqlExData"]).items():
                value = send_jdbc_request(value)
                self.add_to_all_vars(key, value)
            self.log_extraction("JDBC提取", self.case["sqlExData"])


class ReExtractor(Extractor):
    """正则提取类"""

    @allure.step("4.正则提取")
    def extract(self, res):
        if self.case["reExData"]:
            for key, value in self.eval_data(self.case["reExData"]).items():
                # value:表达式
                v = re_match_value(str(res), value)
                self.add_to_all_vars(key, v)

            self.log_extraction("正则提取", self.case["reExData"])


def perform_extractions(case, all_vars, response):
    """
    执行提取器的入口
    :param case: 测试用例
    :param all_vars: 全局变量
    :param response: 接口返回结果-json
    :return:
    """
    # 创建一个列表，里面是所有提取器的类的实例化对象
    extractions = [
        JsonExtractor(case, all_vars),
        JDBCExtractor(case, all_vars),
        ReExtractor(case, all_vars)
    ]

    # 遍历对象
    for extractor in extractions:
        try:
            # 判断对象是正则提取还是json提取还是sql提取
            # 正则提取和json提取都需要传入response
            if isinstance(extractor, JsonExtractor) or isinstance(extractor, ReExtractor):
                extractor.extract(response)
            elif isinstance(extractor, JDBCExtractor):
                extractor.extract()
        except Exception as e:
            logging.error(f"在执行{type(extractor).__name__}发生错误：{e}")
